package com.morningstar.flow.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.morningstar.common.result.ServiceCheckResult;
import com.morningstar.flow.antvX6.BpmnConvert;
import com.morningstar.flow.antvX6.NodeConvert;
import com.morningstar.flow.antvX6.common.Node;
import com.morningstar.flow.antvX6.edge.Edge;
import com.morningstar.flow.dao.entity.FlowNode;
import com.morningstar.flow.dao.entity.FlowProcess;
import com.morningstar.flow.dao.mapper.FlowProcessMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

import static com.morningstar.flow.constants.FlowStatus.PROCESS_DEPLOY_OK;
import static com.morningstar.flow.constants.FlowStatus.PROCESS_STATUS_DEPLOY;

@Slf4j
@Service
public class FlowProcessService extends ServiceImpl<FlowProcessMapper, FlowProcess> {

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private FlowProcessMapper processMapper;

    @Resource
    private FlowNodeService nodeService;

    @Transactional(rollbackFor = Exception.class)
    public void deploy(FlowProcess flowProcess) {
        List<Node> nodeList = NodeConvert.convert(flowProcess);
        BpmnModel bpmnModel = BpmnConvert.convert(flowProcess, nodeList);
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                .category(flowProcess.getProcessGroupName())
                .name(flowProcess.getProcessName())
                .addBpmnModel(flowProcess.getProcessKey() + ".bpmn20.xml", bpmnModel)
                .key(flowProcess.getProcessKey());
        Deployment deployment = deploymentBuilder.deploy();
        log.info("流程部署成功，部署ID：{}", deployment.getId());
        // 更新流程状态为已部署
        flowProcess.setDeploy(PROCESS_DEPLOY_OK);
        flowProcess.setStatus(PROCESS_STATUS_DEPLOY);
        processMapper.updateById(flowProcess);
        // 根据流程Id删除节点
        LambdaQueryWrapper<FlowNode> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(FlowNode::getProcessId, flowProcess.getProcessId());
        nodeService.remove(deleteWrapper);
        List<FlowNode> flowNodes = new ArrayList<>(nodeList.size());
        for (Node node : nodeList) {
            FlowNode flowNode = new FlowNode();
            flowNode.setProcessId(flowProcess.getProcessId());
            flowNode.setProcessDefineKey(flowProcess.getProcessKey());
            flowNode.setNodeActivityId(node.getCName());
            flowNode.setNodeName(node.getNodeName());
            flowNode.setNodeType(node.getNodeType());
            flowNode.setNodeConfig(node);
            if (node instanceof Edge) {
                flowNode.setSource(((Edge) node).getSource().getCName());
                flowNode.setTarget(((Edge) node).getTarget().getCName());
            }
            flowNodes.add(flowNode);
        }
        nodeService.saveBatch(flowNodes);
    }

    /**
     * 获取流程管理员
     *
     * @param processDefinitionId 流程定义Id
     * @return 流程管理员Id
     */
    public Long getProcessAdmin(String processDefinitionId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId)
                .singleResult();
        FlowProcess flowProcess = this.lambdaQuery().eq(FlowProcess::getProcessKey, processDefinition.getKey()).one();
        if (flowProcess == null) {
            throw new RuntimeException("流程不存在");
        }
        if (flowProcess.getProcessAdmin() == null) {
            throw new RuntimeException("流程管理员不存在");
        }
        return flowProcess.getProcessAdmin();
    }

    public ServiceCheckResult checkAddAndUpdate(FlowProcess flowProcess) {
        LambdaQueryWrapper<FlowProcess> checkProcessKeyWrapper = new LambdaQueryWrapper<FlowProcess>()
                .eq(FlowProcess::getProcessKey, flowProcess.getProcessKey())
                .ne(flowProcess.getProcessId() != null, FlowProcess::getProcessId, flowProcess.getProcessId());
        if (this.count(checkProcessKeyWrapper) > 0) {
            return new ServiceCheckResult(true, "流程KEY不可重复");
        }
        return new ServiceCheckResult(false);
    }
}
